/**
  ******************************************************************************
  * @file           : test_1.cpp
  * @author         : wangyingjie
  * @brief          : None
  * @attention      : None
  * @date           : 2025/6/20
  ******************************************************************************
  */


#ifdef WIN32 // for windows
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <time.h>
#include "controlcan.h"
#pragma comment(lib, "controlcan.lib")
#define msleep(ms) Sleep(ms)
typedef HANDLE pthread_t;
#else // for linux
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include "controlcan.h"
#define msleep(ms) usleep((ms) * 1000)
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif

#define MAX_CHANNELS 4
#define CHECK_POINT 200
#define RX_WAIT_TIME 100
#define RX_BUFF_SIZE 1000

unsigned gDevType = 0;  // 设备类型号
unsigned gDevIdx = 0;   // 设备索引，第一个设备是0，第二个相同信号设备是1
unsigned gChMask = 0;   // 通道掩码，CAN0 = 1，CAN1=2，CAN0+CAN1=3
unsigned gBaud = 0;     // 波特率
unsigned gTxType = 0;   // 发送类型，正常发送=0，单次发送=1，自发自收=2，单次自发自收=3
unsigned gTxSleep = 0;  // 发送帧间隔
unsigned gTxFrames = 0; // 每次发送帧数
unsigned gTxCount = 0;  // 发送次数

// 将字符串表示的十六进制数转换为无符号整数
unsigned s2n(const char *s)
{
    unsigned l = strlen(s);
    unsigned v = 0;
    unsigned h = (l > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
    unsigned char c;
    unsigned char t;
    if (!h)
        return atoi(s);
    if (l > 10)
        return 0;
    for (s += 2; c = *s; s++)
    {
        if (c >= 'A' && c <= 'F')
            c += 32;
        if (c >= '0' && c <= '9')
            t = c - '0';
        else if (c >= 'a' && c <= 'f')
            t = c - 'a' + 10;
        else
            return 0;
        v = (v << 4) | t;
    }
    return v;
}

typedef struct
{
    unsigned channel; // channel index, 0~3   通道索引
    unsigned stop;    // stop RX-thread   停止接受线程标志
    unsigned total;   // total received   接收到的总数据量
    unsigned error;   // error(s) detected   错误数量
} RX_CTX;

#ifdef WIN32
unsigned __stdcall rx_thread(void *data)
#else
void *rx_thread(void *data)
#endif
{
    RX_CTX *ctx = (RX_CTX *)data;
    ctx->total = 0; // reset counter  重置计数器

    VCI_CAN_OBJ can[RX_BUFF_SIZE]; // buffer
    int cnt;                       // current received
    int i;

    unsigned check_point = 0;
    while (!ctx->stop) // 在不停止的情况下
    {
        cnt = VCI_Receive(gDevType, gDevIdx, ctx->channel, can, RX_BUFF_SIZE, RX_WAIT_TIME); // 接受函数，返回读取到的帧数
        if (!cnt)
            continue;
        for (i = 0; i < cnt; i++)
        {
            printf("ID: 0X%X  ", can[i].ID);
            printf("TimeStamp: %d  ", can[i].TimeStamp);
            printf("Data: ");
            for (int j = 0; j < can[i].DataLen; j++)
            {
                printf("%02X ", can[i].Data[j]);
            }
            printf("\n");
        }
    }
    printf("CAN%d RX thread terminated\n", ctx->channel);

#ifdef WIN32
    _endthreadex(0);
    return 0;
#else
    pthread_exit(0);
#endif
}

int test()
{
    // ----- init & start -------------------------------------------------

    // 板卡初始化结构体
    VCI_INIT_CONFIG config;
    config.AccCode = 0;            //  验收码
    config.AccMask = 0xffffffff;   // 屏蔽码
    config.Filter = 1;             // 滤波方式，1表示单滤波，0表示双滤波
    config.Mode = 0;               // 0表示正常模式，1表示只听模式
    config.Timing0 = gBaud & 0xff; // 波特率定时器0
    config.Timing1 = gBaud >> 8;   // 波特率定时器1

    int i, j;
    for (i = 0; i < MAX_CHANNELS; i++)
    {
        if ((gChMask & (1 << i)) == 0)
            continue;

        // 初始化CAN通道   设备类型号，设备索引号，第几路CAN，初始化参数结构(VCI_INIT_CONFIG结构体变量)
        if (!VCI_InitCAN(gDevType, gDevIdx, i, &config))
        {
            printf("VCI_InitCAN(%d) failed\n", i);
            return 0;
        }
        printf("VCI_InitCAN(%d) succeeded\n", i);

        // 启动CAN通道   设备类型号，设备索引号，第几路CAN
        if (!VCI_StartCAN(gDevType, gDevIdx, i))
        {
            printf("VCI_StartCAN(%d) failed\n", i);
            return 0;
        }
        printf("VCI_StartCAN(%d) succeeded\n", i);
    }

    VCI_CAN_OBJ can;

    // 创建接收线程
    RX_CTX rx_ctx[MAX_CHANNELS];
    pthread_t rx_threads[MAX_CHANNELS];
    for (i = 0; i < MAX_CHANNELS; i++)
    {
        if ((gChMask & (1 << i)) == 0)
            continue;

        rx_ctx[i].channel = i;
        rx_ctx[i].stop = 0;
        rx_ctx[i].total = 0;
        rx_ctx[i].error = 0;
#ifdef WIN32
        rx_threads[i] = (HANDLE)_beginthreadex(NULL, 0, rx_thread, &rx_ctx[i], 0, NULL);
#else
        pthread_create(&rx_threads[i], NULL, rx_thread, &rx_ctx[i]); // 创建一个新的线程
#endif
    }

    // 停止接收
    printf("<ENTER> to terminate RX-threads...\n");
    getchar();
    for (i = 0; i < MAX_CHANNELS; i++)
    {
        if ((gChMask & (1 << i)) == 0)
            continue;
        rx_ctx[i].stop = 1;
    }
}

int main(int argc, char *argv[])
{
    // if (argc < 5)
    // {
    //     printf("test [DevType] [DevIdx] [ChMask] [Baud]\n"
    //            "    example: test 3 0 1 0x1c00 \n"
    //            "                  | | | |\n"
    //            "                  | | | |0x1400-1M, 0x1c00-500K, 0x1C01-250K ....\n"
    //            "                  | | |\n"
    //            "                  | | |bit0-CAN1, bit1-CAN2, bit2-CAN3, bit3-CAN4, 3=CAN1+CAN2, 7=CAN1+CAN2+CAN3\n"
    //            "                  | |\n"
    //            "                  | |Card0\n"
    //            "                  |\n"
    //            "                  |3-usbcan-i, 4-usbcan-ii ....\n");
    //     return 0;
    // }
    // gDevType = s2n(argv[1]);
    // gDevIdx = s2n(argv[2]);
    // gChMask = s2n(argv[3]);
    // gBaud = s2n(argv[4]);

    gDevType = s2n("3");
    gDevIdx = s2n("0");
    gChMask = s2n("1");
    gBaud = s2n("0x1c00");
    printf("DevType=%d, DevIdx=%d, ChMask=0x%x, Baud=0x%04x\n", gDevType, gDevIdx, gChMask, gBaud);

    // 打开设备  设备类型号，设备索引号，0
    if (!VCI_OpenDevice(gDevType, gDevIdx, 0))
    {
        printf("VCI_OpenDevice failed\n");
        return 0;
    }
    printf("VCI_OpenDevice succeeded\n");

    test();

    // 关闭设备  设备类型号，设备索引号
    VCI_CloseDevice(gDevType, gDevIdx);
    printf("VCI_CloseDevice\n");
    return 0;
}